<?php

namespace humhub\modules\api\controllers;

use Yii;
use yii\web\HttpException;

use yii\filters\auth\CompositeAuth;
use yii\filters\auth\HttpBearerAuth;
use humhub\modules\user\models\User;

use humhub\modules\api\models\Sxb;
use humhub\modules\api\models\SxbRoom;
use humhub\modules\api\models\SxbRoomInteract;
use humhub\modules\api\models\SxbLive;

/**
 * 腾讯直播接口
 */
class SxbController extends Base4Controller
{

    const SDKAPPID = '1400026861';
    const DEPS_PATH= '/uni-data/deps';

    const BIZID = '123456';
    const URL   = '';

    /**
     * @inheritdoc
     */
    public function behaviors(){
        $behaviors = parent::behaviors();
        $behaviors['authenticator'] = [
            'class' => CompositeAuth::className(),
            'authMethods' => [
                //QueryParamAuth::className(),
                HttpBearerAuth::className(),
            ],
        ];

        return $behaviors;
    }

    /**
     * 创建直播-初始化房间
     *
     * GET /api/sxb/login
     *
     * @return 返回userSig和room房间ID
     */
    public function actionLogin(){
        $user = User::findOne(Yii::$app->user->id);
        if( !($user && $user->u_v==1) ){
            throw new HttpException(403, '仅导师可以创建直播');
        }

        $ret = $this->getSig();
        if( $ret ){
            $roomid = $this->getRoom();
            $this->enterRoom($roomid, 1);

            $ret['room'] = $roomid;
            return $ret;
        }
        throw new HttpException(403, '创建失败.');
    }

    /**
     * 成员用户获取Sig
     *
     * GET /api/sxb/userlogin
     *
     * @return 返回userSig和room房间ID
     */
    public function actionUserlogin(){
        $ret = $this->getSig();
        if( $ret ){
            return $ret;
        }
        throw new HttpException(403, '创建失败.');
    }

    /**
     * 心跳接口
     *
     * POST /api/sxb/heart
     *
     * post.thumbup 点赞人数
     *
     * @return boolean
     */
    public function actionHeart(){
        $uid = Yii::$app->user->id;

        $model = SxbRoomInteract::findOne(['uid'=>$uid]);
        if( $model ){
            $model->modify_time= time();
            if( ! $model->save() ){
                throw new HttpException(403, 'heart fail');
            }
        }

        $model = SxbLive::findOne(['host_uid'=>$uid]);
        $admire = (int)Yii::$app->request->post('thumbup');
        if( $model ){
            $model->admire_count= $admire;
            $model->modify_time = time();
            if( ! $model->save() ){
                throw new HttpException(403, 'heart fail');
            }
        }

        $model = Sxb::findOne($uid);
        if( $model ){
            $model->last_request_time = time();
            if( ! $model->save() ){
                throw new HttpException(403, 'heart fail');
            }
        }

        return true;
    }

    /**
     * 主播退出房间
     *
     * GET /api/sxb/exitroom
     *
     * @return boolean
     */
    public function actionExitroom(){
        $model = SxbRoom::findOne(['uid'=>Yii::$app->user->id]);
        if( ! $model ){
            throw new HttpException(403, 'exit fail');
        }
        $roomid = $model->id;
        $host_uid = $model->uid;

        //DELETE FROM t_new_live_record WHERE FIELD_HOST_UID
        SxbLive::find()->where(['host_uid'=>$host_uid])->delete();

        //清空房间成员
        SxbRoomInteract::deleteAll('av_room_id = :roomid', [':roomid' => $roomid]);

        return true;
    }

    /**
     * 上报房间
     *
     * POST /api/sxb/report
     *
     * - post.room 房间ID
     * - post.type 参考SDK
     * - post.appid 参考SDK
     *
     * @return boolean
     */
    public function actionReport(){
        $model = SxbRoom::findOne(['uid'=>Yii::$app->user->id]);
        if( ! $model ){
            throw new HttpException(403, 'report fail.');
        }
        $roomid = $model->id;
        if( $roomid != Yii::$app->request->post('room') ){
            throw new HttpException(403, 'report fail');
        }
        $user = User::findOne(Yii::$app->user->id);

        $ret = $this->genPlayUrl(self::BIZID, self::URL, $roomid);

        $model = SxbLive::findOne(['host_uid'=>Yii::$app->user->id]);
        if( ! $model ){
            $model = new SxbLive();
        }

        $model->create_time = date('Y-m-d H:i:s');
        $model->modify_time = date('U');
        $model->appid       = Yii::$app->request->post('appid');
        $model->title       = $user->displayName . '的直播';
        $model->cover       = $user->getProfileImage()->getUrl();
        $model->host_uid    = Yii::$app->user->id;
        $model->av_room_id  = $roomid;
        $model->video_type  = Yii::$app->request->post('type');
        $model->chat_room_id= $roomid; //聊天室ID
        //room_type
        //device
        //admire_count 点赞人数
        $model->play_url1 = $ret['playUrl1'];
        $model->play_url2 = $ret['playUrl2'];
        $model->play_url3 = $ret['playUrl3'];
        //longitude 经度  
        //latitude 纬度 
        //address 地址

        if( ! $model->save() ){
            throw new HttpException(403, 'report fail .');
        }

        return true;
    }

    /**
     * 房间列表
     *
     * GET /api/sxb/roomlist
     *
     * @return array 其中usernum是用户数
     */
    public function actionRoomlist(){
        $query = SxbLive::find();
        $query->orderBy(['id' => SORT_DESC]);
        //$count = $query->count();

        $pagination = new \yii\data\Pagination([
            'defaultPageSize' => 20,
            'validatePage' => false,
        ]);

        $rooms = $query->offset($pagination->offset)
            ->limit($pagination->limit)
            ->all();

        $u = [];
        foreach($rooms AS $room){
            $user = $room->user;
            $user_num = SxbRoomInteract::find()->where(['av_room_id' => $room->av_room_id])->count();
            $uone['room']        = $room->av_room_id;
            $uone['usernum']     = $user_num;
            $uone['id']          = $user->id;
            $uone['guid']        = $user->guid;
            $uone['profileimage']= $user->getProfileImage()->getUrl();
            $uone['displayname'] = $user->displayName;
            $u[] = $uone;
        }
        return $u;
    }

    /**
     * 成员列表
     *
     * GET /api/sxb/getusers
     *
     * get.room : 房间ID
     *
     * @return array guid用户guid, profileimage:头像, displayname:姓名
     */
    public function actionGetusers(){
        $roomid = (int)Yii::$app->request->get('room');
        $query = SxbRoomInteract::find();

        $pagination = new \yii\data\Pagination([
            'defaultPageSize' => 20,
            'validatePage' => false,
        ]);

        $rooms = $query->where(['av_room_id' => $roomid])
            ->offset($pagination->offset)->limit($pagination->limit)
            ->all();

        $u = [];
        foreach($rooms AS $room){
            $user = $room->user;
            $uone['guid']        = $user->guid;
            $uone['profileimage']= $user->getProfileImage()->getUrl();
            $uone['displayname'] = $user->displayName;
            $uone['u_v']         = $user->u_v;
            $u[] = $uone;
        }
        return $u;
    }

    /**
     * 上报成员(成员进入/退出房间)
     *
     * POST /api/sxb/reportmemid 
     *
     * - post.room : 房间ID
     * - post.operate : =0成员进入房, =1成员退出房间
     *
     * @return array guid用户guid, profileimage:头像, displayname:姓名
     */
    public function actionReportmemid(){
        $operate = (int)Yii::$app->request->post('operate');
        $roomid  = (int)Yii::$app->request->post('room');

        $model = SxbRoomInteract::findOne(['av_room_id'=>$roomid]);
        if( ! $model ){
            throw new HttpException(403, '房间不存在');
        }
        $model = SxbRoomInteract::findOne(['uid'=>Yii::$app->user->id]);

        if( $operate==0 ){
            if( ! $model ){
                $model = new SxbRoomInteract();
            }
            $model->uid        = Yii::$app->user->id;
            $model->av_room_id = $roomid;
            $model->modify_time= time();
            $model->status     ='off';
            $model->role       = 0;
            $ret = $model->save();
        }
        if( $operate==1 ){
            $ret = $model->delete();
        }

        if( !$ret ){
            throw new HttpException(403, 'Server internal error');
        }

        return true;
    }

    /**
     * @inheritdoc
     *  private $status = ''; 上下麦状态 => string; 状态:on-上麦，off-下麦
     *  private $role = 0;    成员角色 => int；0-观众；1-主播；2-上麦成员
     */
    private function enterRoom($roomid, $role=0, $status='off'){
        $model = SxbRoomInteract::findOne(['uid'=>Yii::$app->user->id]);
        if( $model ){
        }else{
            $model = new SxbRoomInteract();
        }

        $model->uid = Yii::$app->user->id;
        $model->av_room_id = $roomid;
        $model->status     = $status;
        $model->modify_time= time();
        $model->role       = $role;
        if( $model->save() ){
            return true;
        }
        throw new HttpException(403, 'enter room fail');
    }
    private function getRoom(){
        $model = SxbRoom::findOne(['uid'=>Yii::$app->user->id]);
        if( $model ){
            //nothing
            $model->last_update_time = time();
            $model->save();
        }else{
            $model = new SxbRoom();
            $model->uid = Yii::$app->user->id;
            $model->last_update_time = time();
            $model->save();

            $model->aux_md5  = md5($model->id . '_' . Yii::$app->user->id . '_aux');
            $model->main_md5 = md5($model->id . '_' . Yii::$app->user->id . '_main');
            $model->save();
        }

        if( $model->id ){
            return $model->id;
        }
        throw new HttpException(403, 'room create fail');
    }
    private function getSig(){
        $private_key = self::DEPS_PATH . '/sig/private_key';
        $public_key  = self::DEPS_PATH . '/sig/public_key';
        $userSig = null;
        $model = Sxb::findOne(Yii::$app->user->id);
        if( $model ){
            $userSig = $model->user_sig;
        }else{
            $model = new Sxb();
        }
        if(empty($userSig)) {
            $userSig = $this->genUserSig(self::SDKAPPID, $private_key);
        } else {
            $ret = $this->verifyUserSig(self::SDKAPPID, $public_key, $userSig);
            if($ret == 1) //过期重新生成
            {
                $userSig = $this->genUserSig(self::SDKAPPID, $private_key);
            }
            else if($ret == -1) 
            {
                throw new HttpException(403, 'Server error: gen sig fail');
            }
        }
        if(empty($userSig))
            throw new HttpException(403, 'Server error: gen sig fail');

        //登录，更新DB
        $model->user_sig = $userSig;
        $model->uid      = Yii::$app->user->id;
        $model->last_request_time = time();
        $model->save();

        $data['userSig'] = $userSig;
        return $data;
    }
    private function verifyUserSig($sdkappid, $public_key_path, $userSig)
    {
        $sig = $this->mktemp();
        if(!$sig) {
            return -1;
        }

        $cmd = 'echo ' . $userSig . '>'. escapeshellarg($sig);
        $ret = exec($cmd, $out, $status);
        if ($status != 0)
        {
            $this->rmtemp($sig);
            return -1;
        }

        $out=array();
        $cmd = self::DEPS_PATH . '/bin/tls_licence_tools'
            . ' ' . 'verify'
            . ' ' . escapeshellarg($public_key_path)
            . ' ' . escapeshellarg($sig)
            . ' ' . escapeshellarg($sdkappid)
            . ' ' . escapeshellarg(Yii::$app->user->id);
        $ret = exec($cmd, $out, $status);

        $this->rmtemp($sig);

        if ($status != 0)
        {
            return -1;
        }
        //return $out[1]; //校验信息
        if($out[0] != 'verify sig ok')
        {
            return 1;
        }

        return 0;
    }
    private function genUserSig($sdkappid, $private_key_path)
    {
        // 创建临时sig文件
        $sig = $this->mktemp();
        if(!$sig) {
            return null;
        }

        // 生成sig
        $cmd = self::DEPS_PATH . '/bin/tls_licence_tools'
            . ' ' . 'gen'
            . ' ' . escapeshellarg($private_key_path)
            . ' ' . escapeshellarg($sig)
            . ' ' . escapeshellarg($sdkappid)
            . ' ' . escapeshellarg(Yii::$app->user->id);
        $ret = exec($cmd, $out, $status);
        if ($status != 0)
        {
            return null;
        }

        // 读取sig
        $out=array();
        $cmd = 'cat ' . ' ' . escapeshellarg($sig);
        $ret = exec($cmd, $out, $status);

        $this->rmtemp($sig);
        if ($status != 0)
        {
            return null;
        }

        return $out[0];
    }
    private function mktemp()
    {
        $cmd = 'mktemp -t -p ' . self::DEPS_PATH . '/sig sxb_sig.XXXXXXXXXX';
        $ret = exec($cmd, $out, $status);
        if ($status != 0)
        {
            return null;
        }
        return $out[0];
    }
    private function rmtemp($tmp)
    {
        $cmd = 'rm -f ' . $tmp;
        $ret = exec($cmd, $out, $status);
        if ($status != 0)
        {
            return false;
        }
        return true;
    }
    private function genPlayUrl($bizId, $url, $roomid)
    {
        $livecode = $roomid . '_' . Yii::$app->user->id;
        //摄像头
        $livecode = $livecode . '_main';

        $md5sum = md5($livecode);
        $livecode = $bizId . '_' . $md5sum; //直播码
        
        return [
            'playUrl1' => 'rtmp://' . $bizId . '.' . $url . $livecode,
            'playUrl2' => 'http://' . $bizId . '.' . $url . $livecode . '.flv',
            'playUrl3' => 'http://' . $bizId . '.' . $url . $livecode . '.m3u8',
        ];
    }
}
